﻿using System;
using LuckyLoot.ServiceFacade.Contracts;
using LuckyLoot.Domain.Entities.People;
using System.Linq;
using LuckyLoot.Domain.ValueObjects;
using LuckyLoot.Common;
using LuckyLoot.Common.Repositories;
using LuckyLoot.Common.Contexts;
using LuckyLoot.Common.Validation;
using System.Collections.Generic;

namespace LuckyLoot.ServiceFacade.Implementation
{
    public class UserService : IUserService
    {
        #region IUserService Members

        public User CreateUser(string name, string phone, string email, string password, string facebook, bool isAdmin, bool isTattooArtist)
        {
            if (string.IsNullOrWhiteSpace(name) ||
                string.IsNullOrWhiteSpace(email) ||
                string.IsNullOrWhiteSpace(password))
                throw new InvalidOperationException("Para criar um usuário é necessário que sejam preenchidos ao menos os campos Nome, E-mail e Senha.");

            var user = isTattooArtist ? new TattooArtist() : new User();
            user.Name = name;
            user.Email = email;
            user.Phone = phone;
            user.Password = password;
            user.Facebook = facebook;
            user.IsAdmin = isAdmin;


            using (var userRepository = new Repository<User, ApplicationContext>())
            {
                var userCount = userRepository.GetByCriteria(u => u.Email.Equals(user.Email, StringComparison.CurrentCultureIgnoreCase)).Count();

                if (userCount > 0)
                    throw new InvalidOperationException("Já existe um usuário cadastrado com esse e-mail. Informe um e-mail diferente.");

                user.Password = Cryptography.Encrypt(user.Password);

                userRepository.Add(user);
                userRepository.Save();
            }

            return user;
        }

        public User UpdateUser(int userID, string name, string phone, string email, string password, string facebook, bool isAdmin, bool isTattooArtist)
        {
            ValidState.Requires<ArgumentNullException>(userID > 0);
            ValidState.Requires<ArgumentException>(!string.IsNullOrWhiteSpace(password));

            if (string.IsNullOrWhiteSpace(name) ||
                string.IsNullOrWhiteSpace(email))
                throw new InvalidOperationException("É necessário que sejam preenchidos ao menos os campos Nome e E-mail.");

            User user;
            using (var userRepository = new Repository<User, ApplicationContext>())
            {
                user = this.GetUser(userID);

                user.Name = name;
                user.Email = email;
                user.Password = password;
                user.Facebook = facebook;
                user.IsAdmin = isAdmin;

                userRepository.Edit(user);
                userRepository.Save();
            }

            return user;
        }

        public User ChangePassword(User user, Password currentPassword, Password newPassword)
        {
            if (user == null || user.Id <= 0)
            {
                throw new InvalidOperationException("O usuário corrente está em um estado inválido. Contate o administrador do sistema.");
            }

            if ((string.IsNullOrWhiteSpace(currentPassword) || string.IsNullOrWhiteSpace(newPassword)))
            {
                throw new InvalidOperationException("Para efetuar a troca de senha é obrigatório que sejam preenchidos todos os campos.");
            }

            // Criptografa as senhas
            var encryptedNewPassword = Cryptography.Encrypt(newPassword);
            var encryptedCurrentPassword = Cryptography.Encrypt(currentPassword);
            
            // Valida se a senha informada é igual à atual
            if (!user.Password.Match(encryptedCurrentPassword))
            {
                throw new InvalidOperationException("A senha atual informada não bate com a senha do usuário.");
            }

            using (var userRepository = new Repository<User, ApplicationContext>())
            {
                user.Password = encryptedNewPassword;
                userRepository.Edit(user);
                userRepository.Save();
            }

            return user;
        }

        public User GetUser(int userID)
        {
            ValidState.Requires<ArgumentNullException>(userID > 0);

            User user = null;
            using (Repository<User, ApplicationContext> repository = new Repository<User, ApplicationContext>())
            {
                user = repository.GetById(userID);
                ValidState.Requires<InvalidOperationException>(user != null, string.Format("Não foi possível encontrar o usuário de id {0}.", userID));
            }

            return user;
        }

        public User GetUser(String userMail)
        {
            ValidState.Requires<ArgumentNullException>(!string.IsNullOrWhiteSpace(userMail));

            User user = null;
            using (Repository<User, ApplicationContext> repository = new Repository<User, ApplicationContext>())
            {
                user = repository.GetByCriteria(u => u.Email.Equals(userMail, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
            }

            return user;
        }

        public TattooArtist GetTattooArtist(int artistID)
        {
            ValidState.Requires<ArgumentNullException>(artistID > 0);

            TattooArtist artist = null;
            using (Repository<TattooArtist, ApplicationContext> repository = new Repository<TattooArtist, ApplicationContext>())
            {
                artist = repository.GetById(artistID);
                ValidState.Requires<InvalidOperationException>(artist != null, string.Format("Não foi possível encontrar o tatuador de id {0}.", artistID));
            }

            return artist;
        }

        
        #endregion

        #region IUserService Members


        public List<User> GetUsers()
        {
            var users = new List<User>();
            using (Repository<User, ApplicationContext> repository = new Repository<User, ApplicationContext>())
            {
                users = repository.GetAll().ToList<User>();
            }

            return users;
        }

        public List<TattooArtist> GetArtists()
        {
            var artists = new List<TattooArtist>();
            using (Repository<TattooArtist, ApplicationContext> repository = new Repository<TattooArtist, ApplicationContext>())
            {
                artists = repository.GetAll().ToList<TattooArtist>();
            }

            return artists;
        }

        #endregion
    }
}
